package org.tio.sitexxx.web.server.controller.minip;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import org.checkerframework.checker.units.qual.C;
import org.redisson.api.annotation.REntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.http.common.HttpRequest;
import org.tio.http.server.annotation.RequestPath;
import org.tio.sitexxx.service.model.main.*;
import org.tio.sitexxx.service.service.qj.MemberService;
import org.tio.sitexxx.service.vo.Const;
import org.tio.sitexxx.web.server.utils.QnUtils;
import org.tio.utils.resp.Resp;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 用户与明星形象数据匹配
 *
 * @author tanlin
 */
@RequestPath("/matching")
public class MatchingController {
    private static Logger log = LoggerFactory.getLogger(MatchingController.class);
    private static final MatchingController me = new MatchingController();

    /**
     * @author tanlin
     */
    public MatchingController() {
    }

    /**
     * 用户是否可以进行形象匹配   post
     *
     * @param request
     * @return
     */
    @RequestPath("/can_you_matching")
    public Resp can_you_matching(HttpRequest request) {
        Map<String, Object> map = JSON.parseObject(request.getBodyString());
        try {
            String openid = (String) map.get("openid");
            if (StrUtil.isBlank(openid)) return Resp.fail("参数错误");
            String sql = "select * from member where openid=?";
            Member member = Member.dao.findFirst(sql, openid);
            if (null == member) return Resp.fail("用户不存在");
            if (null == member.getTested()) return Resp.fail("您还未参加形象测试，无法为您匹配");
            if ("1".equals(member.getTested())) return Resp.fail("您的形象数据暂未分析，奇纪顾问会尽快为您分析");
            //判断次数
            String getShare = "select * from star_share where memberId=?";
            StarShare starShare = StarShare.dao.findFirst(getShare, member.getId());
            if (starShare == null) {
                Record record = new Record().set("memberId", member.getId()).set("free_times", 15);
                Db.use(Const.Db.TIO_SITE_MAIN).save("star_share", record);
            } else {
                if (starShare.getFreeTimes() == 0 && starShare.getShareTimes() < 3) {
                    return Resp.fail("您的免费次数已经用完，分享可免费获得15次体验机会");
                } else if (starShare.getShareTimes() >= 3) {
                    long current_time = System.currentTimeMillis();
                    if (current_time >= starShare.getFreeUntil()) {
                        return Resp.fail("您的一百天免费体验时间已到期，分享可免费可再次获得一百天免费体验机会哦");
                    }
                }
            }
            if ("0".equals(member.getTested())) return Resp.ok();
            return Resp.fail();
        } catch (RuntimeException e) {
            if (e instanceof NullPointerException) {
                return Resp.fail("参数错误");
            }
            log.error(e.toString(), e);
            throw e;
        } catch (Exception se) {
            log.error(se.toString(), se);
        }
        return Resp.fail();
    }

    /**
     * 获取明星的类别
     * 点进明星类别详情之前用，顾问手动添加图片的时候用。
     * 后者在选择了类别的时候，还要可以选择给以前添加过的明星上传更多的造型，或者是修改，或者是上传新的明星新的造型
     *
     * @return
     */
    @RequestPath("/category")
    public Resp getCategory() {
        String sql = "SELECT * FROM star_category";
        return Resp.ok(StarCategory.dao.find(sql));
    }

    /**
     * 获取已经添加的明星造型
     *
     * @param type
     * @return
     */
    @SuppressWarnings("unchecked")
    @RequestPath("/category/detail")
    public Resp getDetails(Integer type) {
        if (null == type) return Resp.fail();
        String get_star = "SELECT * FROM star where type=?";
        String get_star_style = "SELECT * FROM qj_main.star_style where star_id=?";
        List<Star> stars = Star.dao.find(get_star, type);
        System.out.println(stars.size());
        ArrayList<Map<String, Object>> resultList = new ArrayList<>(12);
        stars.forEach(star -> {
            int star_id = star.getId();
            Map<String, Object> temp = JSON.parseObject(JSON.toJSONString(star), Map.class);
            List<StarStyle> styles = StarStyle.dao.find(get_star_style, star_id);
            temp.put("star_detail", styles);
            resultList.add(temp);
        });
        return Resp.ok(resultList);
    }

    /**
     * 修改明星造型
     *
     * @param request
     * @return
     */
    @RequestPath("/category/detail/update")
    public Resp update_star(HttpRequest request) {
        Map<String, Object> map = JSON.parseObject(request.getBodyString());
        try {
            Integer style_id = Integer.valueOf(map.get("id").toString());
            //暂时不让把图片都给换了
            String new_style = map.get("style").toString();
            String sql = "UPDATE star_style SET style =? WHERE (id= ?)";
            int result = Db.use(Const.Db.TIO_SITE_MAIN).update(sql, new_style, style_id);
            if (result == 1) return Resp.ok("修改成功");
            return Resp.fail("修改失败");
        } catch (Exception e) {
            if (e instanceof NullPointerException || e instanceof NumberFormatException ){
                return Resp.fail("参数错误");
            }
            return Resp.fail("error");
        }
    }

    /**
     * 添加已有的明星的新造型
     *
     * @param request
     * @return
     */
    @RequestPath("/category/detail/add")
    public Resp add_categoty_star(HttpRequest request) {
        Map<String, Object> map = JSON.parseObject(request.getBodyString());
        try {
            Integer star_id = Integer.valueOf(map.get("star_id").toString());
            String style = map.get("style").toString();
            String star_image = map.get("star_image").toString();
            String name = map.get("name").toString();
            StarStyle starStyle = new StarStyle();
            starStyle.setStarId(star_id);
            starStyle.setStarImage(star_image);
            starStyle.setName(name);
            starStyle.setStyle(style);
            boolean result = starStyle.save();
            if (result) return Resp.ok("添加成功");
            return Resp.fail("添加失败");
        } catch (Exception e) {
            if (e instanceof NullPointerException || e instanceof NumberFormatException ){
                return Resp.fail("参数错误");
            }
            return Resp.fail("error");
        }
    }

    /**
     * 添加新的明星与造型
     * @param request
     * @return
     */
    @RequestPath("/add")
    public Resp add_star(HttpRequest request){
        Map<String, Object> map = JSON.parseObject(request.getBodyString());
        try {
            Integer type = Integer.valueOf(map.get("type").toString());
            String name = map.get("name").toString();
            String star_image = map.get("image").toString();
            Record star_record=new Record().set("image",star_image).set("name",name)
                    .set("type",type);
            Db.use(Const.Db.TIO_SITE_MAIN).save("star","id",star_record);
            //自增id
            int star_id=Integer.valueOf(star_record.get("id").toString());
            String star_styles=map.get("star_styles").toString();
            JSONArray styles = JSON.parseArray(JSON.toJSONString(map.get("star_styles")));
            //插入明星风格详情
            boolean result=Db.tx(()->{
                for (int i = 0; i < styles.size(); i++) {
                    Map<String,Object> star_style=JSON.parseObject(styles.getString(i));
                    String image=star_style.get("star_image").toString();
                    String starStyle=star_style.get("style").toString();
                    String starStyleName=star_style.get("name").toString();
                    if(StrUtil.isBlank(image)||StrUtil.isBlank(starStyle)||StrUtil.isBlank(starStyleName)){
                        throw new NumberFormatException("参数错误");
                    }
                    StarStyle starStyleNew = new StarStyle();
                    starStyleNew.setStarId(star_id);
                    starStyleNew.setStarImage(image);
                    starStyleNew.setName(starStyleName);
                    starStyleNew.setStyle(starStyleName);
                    boolean result1 = starStyleNew.save();
                    if(!result1) return false;
                }
                return true;
            });
            if (result) return Resp.ok("添加成功");
            return Resp.fail("添加失败");
        } catch (Exception e) {
            if (e instanceof NullPointerException || e instanceof NumberFormatException ){
                e.printStackTrace();
                return Resp.fail("参数错误");
            }
            e.printStackTrace();
            return Resp.fail("error");
        }
    }

    /**
     * 返回上传七牛图片的文件名
     * @return
     */
    @RequestPath("/get/file/key")
    public Resp getKey(){
        String file_name=System.currentTimeMillis()+".jpg";
        return Resp.ok(file_name);
    }
    /**
     * 随机返回6条明星形象数据给用户 ，供用户选择   get
     *
     * @return
     */
    @RequestPath("/star_list")
    public Resp getStarList(Integer type) {
        if (null == type) return Resp.fail();
        String sql = "SELECT star.*,count(star_id) as star_count FROM qj_main.star left join qj_main.star_style s on s.star_id=star.id " +
                "where type=?  group by star_id ORDER BY star.id LIMIT 6";
        List<Star> RamdonList = Star.dao.find(sql, type);
        if (!RamdonList.isEmpty()) {
            return Resp.ok(RamdonList);
        }
        return Resp.ok("暂无数据");
    }

    /**
     * 返回用户与明星数据匹配结果
     *
     * @param star_id 选择的明星id
     * @param openid  用户openid
     *                少女70% 罗曼50% 优雅50% 古典30%  异域30%
     * @return
     */
    @RequestPath("/result")
    public Resp getMatchingResult(Integer star_id, String openid, Integer pageNum) {
        if (StrUtil.isBlank(openid) || null == star_id || pageNum == null) return Resp.fail("参数错误");
        Map<String, Object> openid_map = new HashMap<>(2);
        openid_map.put("openid", openid);
        Member member = MemberService.me.getMember(openid_map);
        String sql = "select * from imagetesting where memberId=?";
        Imagetesting imagetesting = Imagetesting.dao.findFirst(sql, member.getId());
        if (imagetesting.getStyle() == null) {
            return Resp.fail("您的形象数据暂未生成，请联系奇纪客服让专业老师为您分析");
        }
        //不能是纯数字，纯英文或者纯英文或者空串 数据库中存在此类现象。。
        boolean is_can = (Pattern.compile("[a-zA-Z]*|[0-9]*|[\\u4e00-\\u9fa5]*|\\s+")).matcher(String.valueOf(imagetesting.getStyle())).matches();
        if (is_can) {
            return Resp.fail("您的形象数据异常，请联系奇纪客服让专业老师为您重新分析");
        }
        //次数减一
        String getShare = "select * from star_share where memberId=?";
        StarShare starShare = StarShare.dao.findFirst(getShare, member.getId());
        short share_time = starShare.getShareTimes();
        if (share_time < 3) {
            starShare.setFreeTimes(starShare.getFreeTimes() - 1);
            starShare.update();
        }

        String style = imagetesting.getStyle();
        String star_sql = "select * from star_style where star_id=? limit ?,?";
        StarStyle stars = StarStyle.dao.findFirst(star_sql, star_id,pageNum, 1 );


        Map<String, Object> result_map = new HashMap<>(12);
        ArrayList<Map<String, Object>> style_matching_list = new ArrayList<>();
        if (stars != null) {
            result_map.put("id", stars.getStarId());
            result_map.put("name", stars.getName());
            result_map.put("member_style", style);
            {
                ArrayList<Map<String, Object>> resultMap = MatchingController.me.style_matching(style, stars.getStyle());
                Map<String, Object> heap_temp_map = new HashMap<>(4);
                heap_temp_map.put("matching_result", resultMap);
                heap_temp_map.put("image", stars.getStarImage());
                String recommend = MatchingController.me.get_recommend(resultMap);
                heap_temp_map.put("recommend", recommend);
                style_matching_list.add(heap_temp_map);
            }
            System.out.println("before");
            System.out.println(JSON.toJSONString(style_matching_list));
            //sort  需求改变。现在每次只返回一条明星造型数据
//            MatchingController.me.style_sort(style_matching_list);
            result_map.put("result", style_matching_list);
        }
        return Resp.ok(result_map);
    }

    /**
     * 用户分享接口  分享一次可免费获得五次匹配明星机会
     * 分享两次可免费获得15次匹配明星机会  分享三次可获得一百天免费使用匹配明星机会
     *
     * @param request
     * @return
     */
    @RequestPath("/share")
    public Resp share_matching_result(HttpRequest request) {
        Map<String, Object> map = JSON.parseObject(request.getBodyString());
        try {
            String openid = (String) map.get("openid");
            if (StrUtil.isBlank(openid)) return Resp.fail("参数错误");
            Map<String, Object> query = new HashMap<>(2);
            query.put("openid", openid);
            Member member = MemberService.me.getMember(query);
            String sql = "select * from star_share where memberId=?";
            StarShare starShare = StarShare.dao.findFirst(sql, member.getId());
            short share_time = starShare.getShareTimes();
            int free_time = starShare.getFreeTimes();
            share_time++;
            if (share_time == 3) {
                long now_time = System.currentTimeMillis();
                long free_until = now_time + 3600 * 24 * 100 * 1000*36600;
                starShare.setFreeUntil(free_until);
            } else {
                free_time += 15;
                starShare.setFreeTimes(free_time);
                starShare.setShareTimes(share_time);
            }
            boolean result = starShare.update();
            if (result) return Resp.ok("分享成功");
            return Resp.fail("失败");
        } catch (RuntimeException e) {
            if (e instanceof NullPointerException) {
                return Resp.fail("参数错误");
            }
            log.error(e.toString(), e);
            return Resp.fail();
        }
    }

    /**
     * 返回用户与明星的所有造型数据的匹配的吻合程度，风格匹配原则是大的比例匹配等于或者较小的比例
     * 分 1.推荐模仿2.部分模仿3.不推荐
     *
     * @param member_style 用户style
     * @param star_style   明星  style
     * @return
     */
    public ArrayList<Map<String, Object>> style_matching(String member_style, String star_style) {
        ArrayList<Map<String, Object>> resultMap = new ArrayList<>(12);
        Object[][] memberstyle = MatchingController.me.get_style_proportion(member_style);
        Object[][] starstyle = MatchingController.me.get_style_proportion(star_style);
        for (int i = 0; i < starstyle.length; i++) {
            Map<String, Object> matching_map = new HashMap<>(4);
            Object[] star = starstyle[i];
            for (int j = 0; j < memberstyle.length; j++) {
                Object[] member = memberstyle[j];
                String member_str = (String) member[0];
//                System.out.println("member_str:"+member_str);
                String star_str = (String) star[0];
                if (member_str.equals(star_str) || member_str.contains(star_str)) {
                    int k = 1;
//                    System.out.println("member[k]:"+member[k]);
                    Integer member_proportion = Integer.valueOf(member[k].toString());
                    Integer star_proportion = Integer.valueOf(star[k].toString());
//                    System.out.println("star[k+1]："+star[k+1]);
                    String proportion = star_proportion + (ObjectUtil.isNull(star[k + 1]) ? "%" : "-" + star[k + 1] + "%");
//                    System.out.println("proportion:"+proportion);
                    if (member_proportion > star_proportion) {//如果用户风格比例大于或者等于明星风格比例
                        MatchingController.me.deal_map(matching_map, proportion, star_str, true);
                    } else if (member_proportion == star_proportion) {
                        if ((member[k + 1] != null && star[k + 1] == null) || (member[k + 1] == null && star[k + 1] == null)
                                || (Objects.equals(member[k + 1], star[k + 1]))) {//匹配
                            MatchingController.me.deal_map(matching_map, proportion, star_str, true);
                        } else
                            //不匹配
                            MatchingController.me.deal_map(matching_map, proportion, star_str, false);
                    }
                    break;
                }
            }
            if (matching_map.isEmpty()) {//用户没有明星的该风格
                String star_str = (String) star[0];
                Integer star_proportion = Integer.valueOf(star[1].toString());
                String proportion = star_proportion + (ObjectUtil.isNull(star[2]) ? "%" : "-" + star[2] + "%");
                MatchingController.me.deal_map(matching_map, proportion, star_str, false);
            }
            resultMap.add(matching_map);
        }
        return resultMap;
    }

    /**
     * 返回截取过的二维数组
     * eg:"优雅70%  浪漫50%  异域30-50%  罗曼50%  自然30%"
     *
     * @param style
     * @return
     */
    public Object[][] get_style_proportion(String style) {
        String[] styles = style.split("%");
        int length = styles.length;
        Object result[][] = new Object[length][3];
        for (int i = 0; i < length; i++) {
            Pattern p = Pattern.compile("[\\u4e00-\\u9fa5]+|\\d+");//匹配汉字或者数字
            Matcher m = p.matcher(styles[i]);
            int findIndex = 0;
            while (m.find()) {
                result[i][findIndex] = m.group();
                findIndex++;
            }
        }
        return result;
    }

    /**
     * 返回匹配情况
     *
     * @param resultMap
     * @return
     */
    public String get_recommend(ArrayList<Map<String, Object>> resultMap) {
        String recommend = "";
        int suitable = 0;
        for (Map<String, Object> result : resultMap) {
            Boolean is_matching = (Boolean) result.get("is_matching");
            if (is_matching) {
                suitable++;
            }

        }
        int size = resultMap.size();
        if (suitable == size) recommend = "推荐模仿";
        else if (suitable == 0) recommend = "不推荐";
        else if (suitable < size) recommend = "部分推荐";
        return recommend;
    }

    /**
     * 简单插入排序，推荐模仿在前，部分推荐居中，推荐模仿居末
     *
     * @param resultMap waiting sort
     */
    public void style_sort(ArrayList<Map<String, Object>> resultMap) {
        int size = resultMap.size();
        String recommend = "推荐模仿";
        String not_recommend = "不推荐";
        String some_recommend = "部分推荐";
        int i, j;
        for (i = 1; i < size; i++) {
            String front_recommend = (String) resultMap.get(i).get("recommend");
            String back_recommend = (String) resultMap.get(i - 1).get("recommend");
            boolean swap_flag = (recommend.equals(front_recommend) && some_recommend.equals(back_recommend)) ||
                    (some_recommend.equals(front_recommend) && not_recommend.equals(back_recommend)) ||
                    (recommend.equals(front_recommend) && not_recommend.equals(back_recommend));
            if (swap_flag) {
                Map<String, Object> waiting_swap_map = resultMap.get(i);
                for (j = i - 1; j >= 0 && ((resultMap.get(j).get("recommend").toString().equals(some_recommend) && waiting_swap_map.get("recommend").equals(recommend)) ||
                        (resultMap.get(j).get("recommend").toString().equals(not_recommend) && waiting_swap_map.get("recommend").equals(some_recommend)) ||
                        (resultMap.get(j).get("recommend").toString().equals(not_recommend) && waiting_swap_map.get("recommend").equals(recommend))); j--) {
                    resultMap.set(j + 1, resultMap.get(j));
                }
                resultMap.set(j + 1, waiting_swap_map);
            }
        }
    }

    /**
     * map deal
     *
     * @param map
     * @param proportion
     * @param style
     * @param is_matching
     */
    public void deal_map(Map<String, Object> map, String proportion, String style, boolean is_matching) {
        map.put("proportion", proportion);
        map.put("style", style);
        map.put("is_matching", is_matching);
    }

}
